/**泉鸣开放平台SMS能力接口（https://dev.quanmwl.com）
 * 依赖的nodejs库
 * crypto 					MD5加密
 * zlib,https,url,zlib,qs  	发起http/https请求
 * 环境声明：nodejs版本不能低于V8.5.0 也就是需要支持es6
 * @author 梵幽 2023-1-16
 */
const crypto = require('crypto');

const URL = require('url');
const zlib = require('zlib');
const http = require('http');
const https = require('https');
const qs = require('querystring');


function MD5(data) {
	const _md5 = crypto.createHash('md5');
	return _md5.update(data).digest('hex');
}
/**@function 规范数据类型
 * @param {Object} data 参数对象
 * @param {Array} spec 规范列表
 * @description 随便写的检查的，复制到其他地方不一定适用，性能也不能处理大数据，需要检查数据类型的函数，网上百度就有
 */
function typeSpec(data, spec) {
	let res = {
		code: 0,
		msg: "验证通过"
	}
	for (let i in spec) {
		let temp = spec[i]
		let element = data[temp.keys]
		if (temp.required && !element && element != 0) {
			res.code = -1
			res.msg = `${temp.keys}键值不能为空`
			break
		}
		if (typeof element != temp.type) {
			res.code = -1
			res.msg = `${temp.keys}应该是${temp.type}类型`
			break
		}
	}
	return res
}

class Request {
	// constructor(cookie) {
	// 	this.cookies = [];
	// 	if (cookie !== undefined) {
	// 		this.setCookie(cookie);
	// 	}
	// }
	getHeaders(host, postData) {
		let headers = {
			'Host': host,
			'Pragma': 'no-cache',
			'Connection': 'keep-alive',
			'Cache-Control': 'no-cache',
			'Content-Type': 'application/x-www-form-urlencoded',
			'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4,es;q=0.2',
			'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
			'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1',
		};
		if (this.cookies.length) {
			headers.Cookie = this.cookies.join('; ');
		}
		if (postData != '') {
			headers['Content-Length'] = Buffer.byteLength(postData);
		}
		return headers;
	}
	setCookie(cookie) {
		let cookies = cookie.split(';');
		for (let c of cookies) {
			c = c.replace(/^\s/, '');
			this.cookies.push(c);
		}
		return this;
	}
	request(method, url, params) {
		let postData = qs.stringify(params || {});
		let urlObj = URL.parse(url);
		let protocol = urlObj.protocol;
		let options = {
			hostname: urlObj.host,
			port: urlObj.port,
			path: urlObj.path,
			method: method,
			headers: this.getHeaders(urlObj.host, postData),
		};
		/**
		 * data 响应内容
		 * status 状态码
		 * headers 响应头
		 */
		return new Promise((resolve, reject) => {
			let req = (protocol == 'http:' ? http : https).request(options, (res) => {
				let chunks = [];
				let status = res.statusCode
				let resHeader = res.headers
				res.on('data', (data) => {
					chunks.push(data);
				});
				res.on('end', () => {
					let buffer = Buffer.concat(chunks);
					let encoding = res.headers['content-encoding'];
					if (encoding == 'gzip') {
						zlib.gunzip(buffer, function(err, decoded) {
							let rows = decoded.toString()
							try {
								rows = JSON.parse(rows)
							} catch {
								rows = rows
							}
							resolve({
								data: rows,
								status: status,
								headers: resHeader
							});
						});
					} else if (encoding == 'deflate') {
						zlib.inflate(buffer, function(err, decoded) {
							let rows = decoded.toString()
							try {
								rows = JSON.parse(rows)
							} catch {
								rows = rows
							}
							resolve({
								data: rows,
								status: status,
								headers: resHeader
							});
						});
					} else {
						let rows = buffer.toString()
						try {
							rows = JSON.parse(rows)
						} catch {
							rows = rows
						}
						resolve({
							data: rows,
							status: status,
							headers: resHeader
						});
					}
				});
			});
			req.on('error', (e) => {
				reject(e);
			});
			if (postData != '') {
				req.write(postData);
			}
			req.end();
		})
	}
	get(url) {
		return this.request('GET', url, null);
	}
	post(url, params) {
		return this.request('POST', url, params);
	}
}

class qmAPI extends Request {
	/**@function 构造函数
	 * @param {String} openID 开发者标识
	 * @param {Object} options 配置项 暂无用处 先留着
	 */
	constructor(openID, options) {
		super()
		//openID 开发者标识
		this.openID = openID
		/** @description 配置选项
		 *  sms 发送短信的配置参数 包含apiKey
		 */
		this._options = options || {
			sms: {
				apiKey: ""
			}
		}
	}
	/**@function 更新openID
	 * @param {String} openID 开发者标识
	 */
	updateOpenID(openID) {
		this.openID = openID
	}
	/**@function 更新openID
	 * @param {String} openID 开发者标识
	 */
	updateOptions(options) {
		this._options = options
	}

	/**异步调用 可使用await或Promise两种方法进行异步调用，视实际情况使用
	 * @returns code 处理结果 0为通过 -1是本地有错误 -401是请求被拒绝 其他为请求错误 具体对照https://quanmwl.yuque.com/lx4ve0/vcsmy6/gp2pkg#8sz4
	 * @example await qmAPI.sendSMS()  ||  qmAPI.sendSMS().then().catch()
	 */
	async sendSMS(param = {}) {
		let {
			tel,
			model_id,
			model_args //提交正常json数据就行，内部会做JSON.stringify处理
		} = param
		let openID = this.openID
		let apiKey = this._options.sms.apiKey
		if (typeof apiKey !== 'string' || apiKey.length == 0 || !apiKey) {
			return {
				code: -1,
				msg: 'SMS服务的apiKey不能为空'
			}
		}
		if (typeof openID !== 'string' || openID.length == 0 || !openID) {
			return {
				code: -1,
				msg: 'qmAPI的类中openID有误'
			}
		}
		//规范数据类型
		const spec = [{
			keys: "tel",
			required: true,
			type: "number"
		}, {
			keys: "model_id",
			required: true,
			type: "string"
		}, {
			keys: "model_args",
			required: true,
			type: "object"
		}]
		let validate_res = typeSpec(param, spec)
		if (validate_res.code != 0) {
			return validate_res
		}
		//规范必填项
		model_args = JSON.stringify(model_args) //API需要转换string
		//生成加密数据
		let sign = MD5(`${openID}${apiKey}${tel}${model_id}${model_args}`)
		//发起请求
		const formData = {
			openID,
			tel,
			model_id,
			model_args,
			sign
		}
		let response = await this.post('https://dev.quanmwl.com/v1/sms', formData)
		//判断状态码
		if (Math.floor(response.status/100) != 2) {
			return {
				code: -401,
				status:response.status,
				msg: "拒绝访问||接口未响应本次请求"
			}
		}
		//判断接口code
		let res = response.data
		
		if(res.state==200||res.state=="200"){
			res.code=0
			res.msg=res.mess
		}else{
			res.code=res.state
			res.msg=res.mess
		}
		return res
		
	}
}


module.exports = qmAPI
